﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Kokomo.Mirror.CliMetadata.Signatures
{
	class ArrayTypeSpec : TypeSpec
	{
		public TypeSpec arrayElementType;
		public ArrayShape arrayShape;

		public override bool IsComplete
		{
			get
			{
				bool isComplete =
					(this.arrayElementType != null)
					&& (this.arrayElementType.IsComplete)
					&& (this.arrayShape != null)
					;

				return isComplete;
			}
		}
		public override Type ResolveType(
			Module module,
			bool throwOnError,
			Type[] genericTypeArgs,
			Type[] genericMethodArgs
			)
		{
			if (!this.IsComplete) throw new InvalidOperationException();

			Type elementType = this.arrayElementType.ResolveType(module, throwOnError, genericTypeArgs, genericMethodArgs);
			if ((object)elementType == null)
			{
				if (throwOnError)
					throw new TypeLoadException();
				else
					return null;
			}

			Type arrayType = elementType.MakeArrayType(this.arrayShape.rank);
			return arrayType;
		}

		public override string ToString()
		{
			return this.arrayElementType.ToString() + this.arrayShape.ToString();
		}
		public override bool Equals(object obj)
		{
			ArrayTypeSpec other = obj as ArrayTypeSpec;
			if (other == null) return false;

			bool equals =
				(this.arrayElementType.Equals(other.arrayElementType))
				&& (this.arrayShape.Equals(other.arrayShape))
				;
			return equals;
		}
		public override int GetHashCode()
		{
			int hash = 0;
			if (this.arrayElementType != null) hash ^= this.arrayElementType.GetHashCode();
			if (this.arrayShape != null) hash ^= this.arrayShape.GetHashCode();

			return hash;
		}

		public override bool Matches(
			Type type,
			Module module,
			Type[] genericTypeArguments,
			Type[] genericMethodArguments
			)
		{
			if ((object)type == null) throw new ArgumentNullException("type");
			if ((object)module == null) throw new ArgumentNullException("module");

			if (!type.IsArray) return false;

			Type elementType = type.GetElementType();
			int rank = type.GetArrayRank();

			bool matches =
				(rank == this.arrayShape.rank)
				&& (this.arrayElementType.Matches(elementType, module, genericTypeArguments, genericMethodArguments))
				;
			return matches;
		}

		public override bool Matches(
			Module ownerModule,
			TypeSpec other,
			Module otherModule
			)
		{
			if ((object)ownerModule == null) throw new ArgumentNullException("ownerModule");
			if (other == null) throw new ArgumentNullException("other");
			if ((object)otherModule == null) throw new ArgumentNullException("otherModule");

			ArrayTypeSpec otherArrayTypeSpec = other as ArrayTypeSpec;
			if (otherArrayTypeSpec == null) return false;

			bool matches =
				(this.arrayShape.Equals(otherArrayTypeSpec.arrayShape))
				&& (this.arrayElementType.Matches(ownerModule, otherArrayTypeSpec.arrayElementType, otherModule))
				;

			return matches;
		}
	}
}
